﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Game.geodata;
using Game.model;
using Game.utils;
using java.lang;
using java.util.concurrent;
using lineage2.commons.threading;
using Math = java.lang.Math;
using Object = System.Object;

namespace Game.ai
{
    public class PlayableAI:CharacterAI
    {
        private volatile int thinking = 0;
	/**
	 * Field _intention_arg1. Field _intention_arg0.
	 */
	protected static Object _intention_arg0 = null;
        protected static Object _intention_arg1 = null;
        /**
	 * Field _skill.
	 */
	protected Skill _skill;
	/**
	 * Field _nextAction.
	 */
	private nextAction? _nextAction;
	/**
	 * Field _nextAction_arg0.
	 */
	private Object _nextAction_arg0;
	/**
	 * Field _nextAction_arg1.
	 */
	private Object _nextAction_arg1;
	/**
	 * Field _nextAction_arg2.
	 */
	private bool _nextAction_arg2;
	/**
	 * Field _nextAction_arg3.
	 */
	private bool _nextAction_arg3;
	/**
	 * Field _forceUse.
	 */
	protected bool _forceUse;
	/**
	 * Field _dontMove.
	 */
	private bool _dontMove;
	/**
	 * Field _followTask.
	 */
        static ScheduledFuture _followTask;
	
	/**
	 * Constructor for PlayableAI.
	 * @param actor Playable
	 */
	public PlayableAI(Playable actor):base(actor)
	{
		//super(actor);
	}
    public enum nextAction
    {
        /**
         * Field ATTACK.
         */
        ATTACK,
        /**
         * Field CAST.
         */
        CAST,
        /**
         * Field MOVE.
         */
        MOVE,
        /**
         * Field REST.
         */
        REST,
        /**
         * Field PICKUP.
         */
        PICKUP,
        /**
         * Field INTERACT.
         */
        INTERACT,
        /**
         * Field COUPLE_ACTION.
         */
        COUPLE_ACTION
    }
        
	public override void changeIntention(CtrlIntention intention, Object arg0, Object arg1)
	{
		base.changeIntention(intention, arg0, arg1);
		_intention_arg0 = arg0;
		_intention_arg1 = arg1;
	}
	
	public override void setIntention(CtrlIntention intention, Object arg0, Object arg1)
	{
		_intention_arg0 = null;
		_intention_arg1 = null;
		base.setIntention(intention, arg0, arg1);
	}
	
	protected override void onIntentionCast(Skill skill, Creature target)
	{
		_skill = skill;
		base.onIntentionCast(skill, target);
	}
    public static void setNextAction(nextAction action, Object arg0, Object arg1, bool arg2, bool arg3)
    {
        _nextAction = action;
        _nextAction_arg0 = arg0;
        _nextAction_arg1 = arg1;
        _nextAction_arg2 = arg2;
        _nextAction_arg3 = arg3;
    }
    public bool setNextIntention()
	{
		nextAction nextAction = _nextAction;
		Object nextAction_arg0 = _nextAction_arg0;
		Object nextAction_arg1 = _nextAction_arg1;
		bool nextAction_arg2 = _nextAction_arg2;
		bool nextAction_arg3 = _nextAction_arg3;
		Playable actor = getActor();
		if ((nextAction == null) || actor.isActionsDisabled())
		{
			return false;
		}
		Skill skill;
		Creature target;
		GameObject obj;
		switch (Convert.ToInt32(nextAction))
		{
			case 0:
				if (nextAction_arg0 == null)
				{
					return false;
				}
				target = (Creature) nextAction_arg0;
				_forceUse = nextAction_arg2;
				_dontMove = nextAction_arg3;
				clearNextAction();
				setIntention(CtrlIntention.AI_INTENTION_ATTACK, target);
				break;
			case 1:
				if ((nextAction_arg0 == null) || (nextAction_arg1 == null))
				{
					return false;
				}
				skill = (Skill) nextAction_arg0;
				target = (Creature) nextAction_arg1;
				_forceUse = nextAction_arg2;
				_dontMove = nextAction_arg3;
				clearNextAction();
				if (!skill.checkCondition(actor, target, _forceUse, _dontMove, true))
				{
					if ((skill.getNextAction() == nextAction.ATTACK) && !actor.equals(target))
					{
						setNextAction(nextAction.ATTACK, target, null, _forceUse, false);
						return setNextIntention();
					}
					return false;
				}
				setIntention(CtrlIntention.AI_INTENTION_CAST, skill, target);
				break;
			case 2:
				if ((nextAction_arg0 == null) || (nextAction_arg1 == null))
				{
					return false;
				}
				Location loc = (Location) nextAction_arg0;
				Integer offset = (Integer) nextAction_arg1;
				clearNextAction();
				actor.moveToLocation(loc, offset, nextAction_arg2);
				break;
			case 3:
				actor.sitDown(null);
				break;
			case 5:
				if (nextAction_arg0 == null)
				{
					return false;
				}
				obj = (GameObject) nextAction_arg0;
				clearNextAction();
				onIntentionInteract(obj);
				break;
			case 4:
				if (nextAction_arg0 == null)
				{
					return false;
				}
				obj = (GameObject) nextAction_arg0;
				clearNextAction();
				onIntentionPickUp(obj);
				break;
			case 6:
				if ((nextAction_arg0 == null) || (nextAction_arg1 == null))
				{
					return false;
				}
				target = (Creature) nextAction_arg0;
				Integer socialId = (Integer) nextAction_arg1;
				_forceUse = nextAction_arg2;
				_nextAction = null;
				clearNextAction();
				onIntentionCoupleAction((Player) target, socialId);
				break;
			default:
				return false;
		}
		return true;
	}
        public override void clearNextAction()
	{
		_nextAction = null;
		_nextAction_arg0 = null;
		_nextAction_arg1 = null;
		_nextAction_arg2 = false;
		_nextAction_arg3 = false;
	}
	
	protected override void onEvtFinishCasting(int skill_id, bool success)
	{
		if (!setNextIntention())
		{
			setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
		}
	}
	
	protected override void onEvtReadyToAct()
	{
		if (!setNextIntention())
		{
			onEvtThink();
		}
	}
        protected override void onEvtArrived()
	{
		if (!setNextIntention())
		{
			if ((getIntention() == CtrlIntention.AI_INTENTION_INTERACT) || (getIntention() == CtrlIntention.AI_INTENTION_PICK_UP))
			{
				onEvtThink();
			}
			else
			{
				changeIntention(CtrlIntention.AI_INTENTION_ACTIVE, null, null);
			}
		}
	}
	
	protected override void onEvtArrivedTarget()
	{
		switch (Convert.ToInt32(getIntention()))
		{
			case 3:
				thinkAttack(false);
				break;
			case 4:
				thinkCast(false);
				break;
			case 7:
				thinkFollow();
				break;
			default:
				onEvtThink();
				break;
		}
	}
        protected override void onEvtThink()
	{
		Playable actor = getActor();
		if (actor.isActionsDisabled())
		{
			return;
		}
		try
		{
			if (thinking++ > 1)
			{
				return;
			}
			switch (Convert.ToInt32(getIntention()))
			{
				case 1:
					thinkActive();
					break;
				case 3:
					thinkAttack(true);
					break;
				case 4:
					thinkCast(true);
					break;
				case 5:
					thinkPickUp();
					break;
				case 6:
					thinkInteract();
					break;
				case 7:
					thinkFollow();
					break;
				case 8:
					thinkCoupleAction((Player) _intention_arg0, (Integer) _intention_arg1, false);
					break;
			}
		}
		catch (java.lang.Exception e)
		{
			_log.error("", e);
		}
		finally
		{
			thinking--;
		}
	}
        protected virtual void thinkActive()
        {
        }
        protected void thinkFollow()
        {
            Playable actor = getActor();
            Creature target = (Creature)_intention_arg0;
            Integer offset = (Integer)_intention_arg1;
            if ((target == null) || target.isAlikeDead() || (actor.getDistance(target) > 4000) || (offset == null))
            {
                clientActionFailed();
                return;
            }
            if (actor.isFollow && (actor.getFollowTarget() == target))
            {
                clientActionFailed();
                return;
            }
            if (actor.isInRange(target, offset + 20) || actor.isMovementDisabled())
            {
                clientActionFailed();
            }
            if (_followTask != null)
            {
                _followTask.cancel(false);
                _followTask = null;
            }
            _followTask = ThreadPoolManager.getInstance().schedule(new ThinkFollow(), 250L);
        }
        protected class ThinkFollow:RunnableImpl
        {
            public override void runImpl()
		{
			Playable actor = getActor();
			if (getIntention() != CtrlIntention.AI_INTENTION_FOLLOW)
			{
				if (actor.isClone() && getIntention() == CtrlIntention.AI_INTENTION_ACTIVE)
				{
					((ClonePlayer) actor).setFollowMode(false);
				}
				else if ((actor.isPet() || actor.isServitor()) && (getIntention() == CtrlIntention.AI_INTENTION_ACTIVE))
				{
					((Summon) actor).setFollowMode(false);
				}
				return;
			}
			Creature target = (Creature) _intention_arg0;
                var arg1 = _intention_arg1 is int ? (int) _intention_arg1 : 0;
                int offset = arg1 != null ? arg1 : 0;
			if ((target == null) || target.isAlikeDead() || (actor.getDistance(target) > 4000))
			{
				setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
				return;
			}
			Player player = actor.getPlayer();
			if ((player == null) || player.isLogoutStarted() || ((actor.isPet() || actor.isServitor()) && !player.getSummonList().contains(actor) && !actor.isClone()))
			{
				setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
				return;
			}
			if (!actor.isInRange(target, offset + 20) && (!actor.isFollow || (actor.getFollowTarget() != target)))
			{
				actor.followToCharacter(target, offset, false);
			}
			_followTask = ThreadPoolManager.getInstance().schedule(this, 250L);
		}
        }
        protected class ExecuteFollow:RunnableImpl
        {
            private Creature _target;
		/**
		 * Field _range.
		 */
		private int _range;
		
		/**
		 * Constructor for ExecuteFollow.
		 * @param target Creature
		 * @param range int
		 */
		public ExecuteFollow(Creature target, int range)
		{
			_target = target;
			_range = range;
		}
        public override void runImpl()
        {
            if (_target.isDoor())
            {
                _actor.moveToLocation(_target.getLoc(), 40, true);
            }
            else
            {
                _actor.followToCharacter(_target, _range, true);
            }
        }
        }
        protected override void onIntentionInteract(GameObject obj)
	{
		Playable actor = getActor();
		if (actor.isActionsDisabled())
		{
			setNextAction(nextAction.INTERACT, obj, null, false, false);
			clientActionFailed();
			return;
		}
		clearNextAction();
		changeIntention(CtrlIntention.AI_INTENTION_INTERACT, obj, null);
		onEvtThink();
	}
        protected override void onIntentionCoupleAction(Player player, Integer socialId)
        {
            clearNextAction();
            changeIntention(CtrlIntention.AI_INTENTION_COUPLE_ACTION, player, socialId);
            onEvtThink();
        }
        protected void thinkInteract()
        {
            Playable actor = getActor();
            GameObject target = (GameObject)_intention_arg0;
            if (target == null)
            {
                setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
                return;
            }
            int range = (int)(Math.max(30, actor.getMinDistance(target)) + 20);
            if (actor.isInRangeZ(target, range))
            {
                if (actor.isPlayer())
                {
                    //((Player) actor).doInteract(target);
                    target.onActionSelect((Player)actor, false);
                }
                setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
            }
            else
            {
                actor.moveToLocation(target.getLoc(), 40, true);
                setNextAction(nextAction.INTERACT, target, null, false, false);
            }
        }

        public override void onIntentionPickUp(GameObject obj)
	{
		Playable actor = getActor();
		if (actor.isActionsDisabled())
		{
			setNextAction(nextAction.PICKUP, obj, null, false, false);
			clientActionFailed();
			return;
		}
		clearNextAction();
		changeIntention(CtrlIntention.AI_INTENTION_PICK_UP, obj, null);
		onEvtThink();
	}
        protected void thinkPickUp()
	{
		Playable actor = getActor();
		GameObject target = (GameObject) _intention_arg0;
		if (target == null)
		{
			setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
			return;
		}
		if (actor.isInRange(target, 30) && (Math.abs(actor.getZ() - target.getZ()) < 50))
		{
			if (actor.isPlayer() || actor.isPet())
			{
				actor.doPickupItem(target);
			}
			setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
		}
		else
		{
            actor.moveToLocation(target.getLoc(), 10, true);
            setNextAction(nextAction.PICKUP, target, null, false, false);
		}
	}
    protected virtual void thinkAttack(bool checkRange)
	{
		Playable actor = getActor();
		Player player = actor.getPlayer();
		if (player == null)
		{
			setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
			return;
		}
		if (actor.isActionsDisabled() || actor.isAttackingDisabled())
		{
			actor.sendActionFailed();
			return;
		}
		bool isPosessed = (actor is Summon) && ((Summon) actor).isDepressed();
		Creature attack_target = getAttackTarget();
		if ((attack_target == null) || attack_target.isDead() || (!isPosessed && !(_forceUse ? attack_target.isAttackable(actor) : attack_target.isAutoAttackable(actor))))
		{
			setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
			actor.sendActionFailed();
			return;
		}
		if (!checkRange)
		{
			clientStopMoving();
			actor.doAttack(attack_target);
			return;
		}
		int range = actor.getPhysicalAttackRange();
		if (range < 10)
		{
			range = 10;
		}
		boolean canSee = GeoEngine.canSeeTarget(actor, attack_target, false);
		if (!canSee && ((range > 200) || (Math.abs(actor.getZ() - attack_target.getZ()) > 200)))
		{
			actor.sendPacket(SystemMsg.CANNOT_SEE_TARGET);
			setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
			actor.sendActionFailed();
			return;
		}
		range += actor.getMinDistance(attack_target);
		if (actor.isFakeDeath())
		{
			actor.breakFakeDeath();
		}
		if (actor.isInRangeZ(attack_target, range))
		{
			if (!canSee)
			{
				actor.sendPacket(SystemMsg.CANNOT_SEE_TARGET);
				setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
				actor.sendActionFailed();
				return;
			}
			clientStopMoving(false);
			actor.doAttack(attack_target);
		}
		else if (!_dontMove)
		{
			ThreadPoolManager.getInstance().execute(new ExecuteFollow(attack_target, range - 20));
		}
		else
		{
			actor.sendActionFailed();
		}
	}
    protected virtual void thinkCast(bool checkRange)
    {
        Playable actor = getActor();
        Creature target = getAttackTarget();
        if ((_skill.getSkillType() == SkillType.CRAFT) || _skill.isToggle())
        {
            if (_skill.checkCondition(actor, target, _forceUse, _dontMove, true))
            {
                actor.doCast(_skill, target, _forceUse);
            }
            return;
        }
        if ((target == null) || ((target.isDead() != _skill.getCorpse()) && !_skill.isNotTargetAoE()))
        {
            setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
            actor.sendActionFailed();
            return;
        }
        if (!checkRange)
        {
            if ((_skill.getNextAction() == nextAction.ATTACK) && !actor.equals(target))
            {
                setNextAction(nextAction.ATTACK, target, null, _forceUse, false);
            }
            else
            {
                clearNextAction();
            }
            clientStopMoving();
            if (_skill.checkCondition(actor, target, _forceUse, _dontMove, true))
            {
                actor.doCast(_skill, target, _forceUse);
            }
            else
            {
                setNextIntention();
                if (getIntention() == CtrlIntention.AI_INTENTION_ATTACK)
                {
                    thinkAttack(true);
                }
            }
            return;
        }
        int range = actor.getMagicalAttackRange(_skill);
        if (range < 10)
        {
            range = 10;
        }
        bool canSee = (_skill.getSkillType() == SkillType.TAKECASTLE) || (_skill.getSkillType() == SkillType.TAKEFORTRESS) || GeoEngine.canSeeTarget(actor, target, actor.isFlying());
        bool noRangeSkill = _skill.getCastRange() == 32767;
        if (!noRangeSkill && !canSee && ((range > 200) || (Math.abs(actor.getZ() - target.getZ()) > 200)))
        {
            actor.sendPacket(SystemMsg.CANNOT_SEE_TARGET);
            setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
            actor.sendActionFailed();
            return;
        }
        range += actor.getMinDistance(target);
        if (actor.isFakeDeath())
        {
            actor.breakFakeDeath();
        }
        if (actor.isInRangeZ(target, range) || noRangeSkill)
        {
            if (!noRangeSkill && !canSee)
            {
                actor.sendPacket(SystemMsg.CANNOT_SEE_TARGET);
                setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
                actor.sendActionFailed();
                return;
            }
            if ((_skill.getNextAction() == nextAction.ATTACK) && !actor.equals(target))
            {
                setNextAction(nextAction.ATTACK, target, null, _forceUse, false);
            }
            else
            {
                clearNextAction();
            }
            if (_skill.checkCondition(actor, target, _forceUse, _dontMove, true))
            {
                clientStopMoving(false);
                actor.doCast(_skill, target, _forceUse);
            }
            else
            {
                setNextIntention();
                if (getIntention() == CtrlIntention.AI_INTENTION_ATTACK)
                {
                    thinkAttack(true);
                }
            }
        }
        else if (!_dontMove)
        {
            ThreadPoolManager.getInstance().execute(new ExecuteFollow(target, range - 20));
        }
        else
        {
            actor.sendPacket(Msg.YOUR_TARGET_IS_OUT_OF_RANGE);
            setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
            actor.sendActionFailed();
        }
    }
        protected void thinkCoupleAction(Player target, Integer socialId, boolean cancel)
	{
	}
	protected override void onEvtDead(Creature killer)
	{
		clearNextAction();
		base.onEvtDead(killer);
	}
	
	protected override void onEvtFakeDeath()
	{
		clearNextAction();
		base.onEvtFakeDeath();
	}
	public void lockTarget(Creature target)
	{
		Playable actor = getActor();
		if ((target == null) || target.isDead())
		{
			actor.setAggressionTarget(null);
		}
		else if (actor.getAggressionTarget() == null)
		{
			actor.getTarget();
			actor.setAggressionTarget(target);
			actor.setTarget(target);
			clearNextAction();
		}
	}
    public override void Attack(GameObject target, bool forceUse, bool dontMove)
    {
        Playable actor = getActor();
        if (target.isCreature() && (actor.isActionsDisabled() || actor.isAttackingDisabled()))
        {
            setNextAction(nextAction.ATTACK, target, null, forceUse, false);
            actor.sendActionFailed();
            return;
        }
        _dontMove = dontMove;
        _forceUse = forceUse;
        clearNextAction();
        setIntention(CtrlIntention.AI_INTENTION_ATTACK, target);
    }
    public override void Cast(Skill skill, Creature target, bool forceUse, bool dontMove)
    {
        Playable actor = getActor();
        if (skill.altUse() || skill.isToggle())
        {
            if (((skill.isToggle() && !skill.isAwakeningToggle()) || skill.isHandler()) && (actor.isOutOfControl() || actor.isStunned() || actor.isSleeping() || actor.isParalyzed() || actor.isAlikeDead() || actor.isAirBinded() || actor.isKnockedBack() || actor.isKnockedDown() || actor.isPulledNow()))
            {
                clientActionFailed();
            }
            else
            {
                actor.altUseSkill(skill, target);
            }
            return;
        }
        if (actor.isActionsDisabled())
        {
            setNextAction(nextAction.CAST, skill, target, forceUse, dontMove);
            clientActionFailed();
            return;
        }
        _forceUse = forceUse;
        _dontMove = dontMove;
        clearNextAction();
        setIntention(CtrlIntention.AI_INTENTION_CAST, skill, target);
    }
    public override Playable getActor()
    {
        return (Playable)base.getActor();
    }
    }
}
